/**
	Define IMGUI_AUTO_DISABLE_TEST_WINDOW to disable this feature.
*/

#ifndef IMGUI_AUTO_DISABLE_TEST_WINDOW
#	include <vector>
#	include <map>
#	include <set>
#	include <deque>
#	include <tuple>
#	include <array>
#	include <list>
#endif

#include "../auto.h"
#include "../imgui.h"
#include "core.h"
#include "impl_base.h"

#ifndef IMGUI_AUTO_DISABLE_TEST_WINDOW
#	ifdef _IMGUI_AUTO_GLM_
#		include <glm/gtx/transform.hpp>
#	endif
#endif

#ifndef IMGUI_AUTO_DISABLE_TEST_WINDOW
void ImGui::ShowAutoTestWindow()
{
	if (!ImGui::Begin("ImGui::Auto() Test Window")) { ImGui::End(); return; }
	auto myCollapsingHeader = [](const char* name)->bool
	{
		ImGuiStyle & style = ImGui::GetStyle();
		ImGui::PushStyleColor(ImGuiCol_Header, style.Colors[ImGuiCol_Button]);
		ImGui::PushStyleColor(ImGuiCol_HeaderHovered, style.Colors[ImGuiCol_ButtonHovered]);
		ImGui::PushStyleColor(ImGuiCol_HeaderActive, style.Colors[ImGuiCol_ButtonActive]);
		bool b = ImGui::CollapsingHeader(name);
		ImGui::PopStyleColor(3);
		return b;
};
	if (myCollapsingHeader("About ImGui::Auto()"))
	{
		ImGui::Auto(R"comment(
ImGui::Auto() is one simple function that can create GUI for almost any data structure using ImGui functions.
a. Your data is presented in tree-like structure that is defined by your type.
    The generated code is highly efficient.
b. Const types are display only, the user cannot modify them.
    Use ImGui::as_cost() to permit the user to modify a non-const type.
The following types are supported (with nesting):
1 Strings. Flavours of std::string and char*. Use std::string for input.
2 Numbers. Integers, Floating points, ImVec{2,4}
3 STL Containers. Standard containers are supported. (std::vector, std::map,...)
The contained type has to be supported. If it is not, see 8.
4 Pointers, arrays. Pointed type must be supported.
5 std::pair, std::tuple. Types used must be supported.
6 structs and simple classes! The struct is converted to a tuple, and displayed as such.
    * Requirements: C++14 compiler (GCC-5.0+, Clang, Visual Studio 2017 with /std:c++17, ...)
    * How? I'm using this libary https://github.com/apolukhin/magic_get (ImGui::Auto() is only VS2017 C++17 tested.)
7 Functions. A void(void) type function becomes simple button.
For other types, you can input the arguments and calculate the result.
Not yet implemented!
8 You can define ImGui::Auto() for your own type! Use the following macros:
    * IMGUI_AUTO_DEFINE_INLINE(template_spec, type_spec, code)	single line definition, teplates shouldn't have commas inside!
    * IMGUI_AUTO_DEFINE_BEGIN(template_spec, type_spec)        start multiple line definition, no commas in arguments!
    * IMGUI_AUTO_DEFINE_BEGIN_P(template_spec, type_spec)      start multiple line definition, can have commas, use parentheses!
    * IMGUI_AUTO_DEFINE_END                                    end multiple line definition with this.
where
    * template_spec   describes how the type is templated. For fully specialized, use "template<>" only
    * type_spec       is the type for witch you define the ImGui::Auto() function.
	* var             will be the generated function argument of type type_spec.
	* name            is the const std::string& given by the user, and/or generated by the caller ImGui::Auto function
Example:           IMGUI_AUTO_DEFINE_INLINE(template<>, bool, ImGui::Checkbox(name.c_str(), &var);)
Tipps: - You may use ImGui::Auto_t<type>::Auto(var, name) functions directly.
        - Check imgui::detail namespace for other helper functions.

The libary uses partial template specialization, so definitions can overlap, the most specialized will be chosen.
However, using large, nested structs can lead to slow compilation.
Container data, large structs and tuples are hidden by default.
)comment");
		if(ImGui::TreeNode("TODO-s"))
		{
			ImGui::Auto(R"todos(
	1	Insert items to (non-const) set, map, list, ect
	2	Call any function or function object.
	3	Deduce function arguments as a tuple. User can edit the arguments, call the function (button), and view return value.
	4	All of the above needs self ImGui::Auto() allocated memmory. Current plan is to prioritize low memory usage
		over user experiance. (Beacuse if you want good UI, you code it, not generate it.)
		Plan A:
			a)	Data is stored in a map. Key can be the presneted object's address.
			b)	Data is allocated when not already present in the map
			c)	std::unique_ptr<void, deleter> is used in the map with deleter function manually added (or equivalent something)
			d)	The first call for ImGui::Auto at every few frames should delete
				(some of, or) all data that was not accesed in the last (few) frames. How?
		This means after closing a TreeNode, and opening it, the temporary values might be deleted and recreated.
)todos");
			ImGui::TreePop();
		}
	}
	if (myCollapsingHeader("1. String"))
	{
		ImGui::Indent();

		ImGui::Auto(R"code(
	ImGui::Auto("Hello Imgui::Auto() !"); //This is how this text is written as well.)code");
		ImGui::Auto("Hello Imgui::Auto() !"); //This is how this text is written as well.

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static std::string str = "Hello ImGui::Auto() for strings!";
	ImGui::Auto(str, "asd");)code");
		static std::string str = "Hello ImGui::Auto() for strings!";
		ImGui::Auto(str, "str");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static std::string str2 = "ImGui::Auto()\n Automatically uses multiline input for strings!\n:)";
	ImGui::Auto(str2, "str2");)code");
		static std::string str2 = "ImGui::Auto()\n Automatically uses multiline input for strings!\n:)";
		ImGui::Auto(str2, "str2");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static const std::string conststr = "Const types are not to be changed!";
	ImGui::Auto(conststr, "conststr");)code");
		static const std::string conststr = "Const types are not to be changed!";
		ImGui::Auto(conststr, "conststr");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	char * buffer = "To edit a string use std::string. Manual buffers are unwelcome here.";
	ImGui::Auto(buffer, "buffer");)code");
		char * buffer = "To edit a string use std::string. Manual buffers are unwelcome here.";
		ImGui::Auto(buffer, "buffer");

		ImGui::Unindent();
	}
	if (myCollapsingHeader("2. Numbers"))
	{
		ImGui::Indent();

		ImGui::Auto(R"code(
	static int i = 42;
	ImGui::Auto(i, "i");)code");
		static int i = 42;
		ImGui::Auto(i, "i");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static float f = 3.14;
	ImGui::Auto(f, "f");)code");
		static float f = 3.14;
		ImGui::Auto(f, "f");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static ImVec4 f4 = {1.5f,2.1f,3.4f,4.3f};
	ImGui::Auto(f4, "f4");)code");
		static ImVec4 f4 = {1.5f,2.1f,3.4f,4.3f};
		ImGui::Auto(f4, "f4");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static const ImVec2 f2 = {1.f,2.f};
	ImGui::Auto(f2, "f2");)code");
		static const ImVec2 f2 = {1.f,2.f};
		ImGui::Auto(f2, "f2");

		ImGui::Unindent();
	}
	if (myCollapsingHeader("3. Containers"))
	{
		ImGui::Indent();

		ImGui::Auto(R"code(
	static std::vector<std::string> vec = { "First string","Second str",":)" };
	ImGui::Auto(vec,"vec");)code");
		static std::vector<std::string> vec = { "First string","Second str",":)" };
		ImGui::Auto(vec, "vec");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static const std::vector<float> constvec = { 3,1,2.1f,4,3,4,5 };
	ImGui::Auto(constvec,"constvec");	//Cannot change vector, nor values)code");
		static const std::vector<float> constvec = { 3,1,2.1f,4,3,4,5 };
		ImGui::Auto(constvec, "constvec");	//Cannot change vector, nor values

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static std::vector<bool> bvec = { false, true, false, false };
	ImGui::Auto(bvec,"bvec");)code");
		static std::vector<bool> bvec = { false, true, false, false };
		ImGui::Auto(bvec, "bvec");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static const std::vector<bool> constbvec = { false, true, false, false };
	ImGui::Auto(constbvec,"constbvec");
	)code");
		static const std::vector<bool> constbvec = { false, true, false, false };
		ImGui::Auto(constbvec, "constbvec");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static std::map<int, float> map = { {3,2},{1,2} };
	ImGui::Auto(map, "map");	// insert and other operations)code");
		static std::map<int, float> map = { {3,2},{1,2} };
		ImGui::Auto(map, "map");	// insert and other operations

		if (ImGui::TreeNode("All cases"))
		{
			ImGui::Auto(R"code(
	static std::deque<bool> deque = { false, true, false, false };
	ImGui::Auto(deque,"deque");)code");
			static std::deque<bool> deque = { false, true, false, false };
			ImGui::Auto(deque, "deque");

			ImGui::NewLine(); ImGui::Separator();

			ImGui::Auto(R"code(
	static std::set<char*> set = { "set","with","char*" };
	ImGui::Auto(set,"set");)code");
			static std::set<char*> set = { "set","with","char*" }; //for some reason, this does not work
			ImGui::Auto(set, "set");	// the problem is with the const iterator, but

			ImGui::NewLine(); ImGui::Separator();

			ImGui::Auto(R"code(
	static std::map<char*, std::string> map = { {"asd","somevalue"},{"bsd","value"} };
	ImGui::Auto(map, "map");	// insert and other operations)code");
			static std::map<char*, std::string> map = { {"asd","somevalue"},{"bsd","value"} };
			ImGui::Auto(map, "map");	// insert and other operations

			ImGui::TreePop();
		}
		ImGui::Unindent();
	}
	if (myCollapsingHeader("4. Pointers and Arrays"))
	{
		ImGui::Indent();

		ImGui::Auto(R"code(
	static float *pf = nullptr;
	ImGui::Auto(pf, "pf");)code");
		static float *pf = nullptr;
		ImGui::Auto(pf, "pf");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static int i=10, *pi=&i;
	ImGui::Auto(pi, "pi");)code");
		static int i = 10, *pi = &i;
		ImGui::Auto(pi, "pi");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static const std::string cs= "I cannot be changed!", * cps=&cs;
	ImGui::Auto(cps, "cps");)code");
		static const std::string cs = "I cannot be changed!", *cps = &cs;
		ImGui::Auto(cps, "cps");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static std::string str = "I can be changed! (my pointee cannot)";
	static std::string *const strpc = &str;)code");
		static std::string str = "I can be changed! (my pointee cannot)";
		static std::string *const strpc = &str;
		ImGui::Auto(strpc, "strpc");

		ImGui::NewLine(); ImGui::Separator();
		ImGui::Auto(R"code(
	static std::array<float,5> farray = { 1.2, 3.4, 5.6, 7.8, 9.0 };
	ImGui::Auto(farray, "std::array");)code");
		static std::array<float, 5> farray = { 1.2, 3.4 , 5.6, 7.8, 9.0};
		ImGui::Auto(farray, "std::array");


		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static float farr[5] = { 1.2, 3.4, 5.6, 7.8, 9.0 };
	ImGui::Auto(farr, "float[5]");)code");
		static float farr[5] = { 11.2, 3.4, 5.6, 7.8, 911.0 };
		ImGui::Auto(farr, "float[5]");

		ImGui::Unindent();
	}
	if(myCollapsingHeader("5. Pairs and Tuples"))
	{
		ImGui::Indent();

		ImGui::Auto(R"code(
	static std::pair<bool, ImVec2> pair = { true,{2.1f,3.2f} };
	ImGui::Auto(pair, "pair");)code");
		static std::pair<bool, ImVec2> pair = { true,{2.1f,3.2f} };
		ImGui::Auto(pair, "pair");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static std::pair<int, std::string> pair2 = { -3,"simple types appear next to each other in a pair" };
	ImGui::Auto(pair2, "pair2");)code");
		static std::pair<int, std::string> pair2 = { -3,"simple types appear next to each other in a pair" };
		ImGui::Auto(pair2, "pair2");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	ImGui::Auto(ImGui::as_const(pair), "as_const(pair)"); //easy way to view as const)code");
		ImGui::Auto(ImGui::as_const(pair), "as_const(pair)"); //easy way to view as const

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	std::tuple<const int, std::string, ImVec2> tuple = { 42, "string in tuple", {3.1f,3.2f} };
	ImGui::Auto(tuple, "tuple");)code");
		std::tuple<const int, std::string, ImVec2> tuple = { 42, "string in tuple", {3.1f,3.2f} };
		ImGui::Auto(tuple, "tuple");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	const std::tuple<int, const char*, ImVec2> consttuple = { 42, "smaller tuples are inlined", {3.1f,3.2f} };
	ImGui::Auto(consttuple, "consttuple");)code");
		const std::tuple<int, const char*, ImVec2> consttuple = { 42, "Smaller tuples are inlined", {3.1f,3.2f} };
		ImGui::Auto(consttuple, "consttuple");


		ImGui::Unindent();
	}
	if (myCollapsingHeader("6. Structs!!"))
	{
		ImGui::Indent();

		ImGui::Auto(R"code(
	struct A //Structs are automagically converted to tuples!
	{
		int i = 216;
		bool b = true;
	};
	static A a;
	ImGui::Auto("a", a);)code");
		struct A
		{
			int i = 216;
			bool b = true;
		};
		static A a;
		ImGui::Auto(a, "a");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	ImGui::Auto(ImGui::as_const(a), "as_const(a)");// const structs are possible)code");
		ImGui::Auto(ImGui::as_const(a), "as_const(a)");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	struct B
	{
		std::string str = "Unfortunatelly, cannot deduce const-ness from within a struct";
		const A a = A();
	};
	static B b;
	ImGui::Auto(b, "b");)code");
		struct B
		{
			std::string str = "Unfortunatelly, cannot deduce const-ness from within a struct";
			const A a = A();
		};
		static B b;
		ImGui::Auto(b, "b");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static std::vector<B> vec = { {"vector of structs!", A()}, B() };
	ImGui::Auto(vec, "vec");)code");
		static std::vector<B> vec = { {"vector of structs!", A()}, B() };
		ImGui::Auto(vec, "vec");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	struct C
	{
		std::list<B> vec;
		A *a;
	};
	static C c = { {{"Container inside a struct!", A() }}, &a };
	ImGui::Auto(c, "c");)code");
		struct C
		{
			std::list<B> vec;
			A *a;
		};
		static C c = { {{"Container inside a struct!", A() }}, &a };
		ImGui::Auto(c, "c");

		ImGui::Unindent();
	}
	if (myCollapsingHeader("Functions"))
	{
		ImGui::Indent();

		ImGui::Auto(R"code(
	void (*func)() = []() { ImGui::TextColored(ImVec4(0.5, 1, 0.5, 1.0), "Button pressed, function called :)"); };
	ImGui::Auto(func, "void(void) function");)code");
		void(*func)() = []() { ImGui::SameLine(); ImGui::TextColored(ImVec4(0.5, 1, 0.5, 1.0), "Button pressed, function called :)"); };
		ImGui::Auto(func, "void(void) function");

		ImGui::Unindent();
	}
#ifdef _IMGUI_AUTO_GLM_
	if (myCollapsingHeader("GLM functions"))
	{
		ImGui::Auto(R"code(
	static glm::vec2 v2 = { 1.3f,2.f };
	ImGui::Auto(v2,"v2");)code");
		static glm::vec2 v2 = { 1.3f,2.f };
		ImGui::Auto(v2,"v2");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	ImGui::Auto(glm::vec3(v2, 1.f), "v3"); //does not call the const variant. Use as_const()  if that is a problem!)code");
		ImGui::Auto(glm::vec3(v2, 1.f), "v3");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static glm::vec4 v4 = glm::vec4(v2, 3.14f,1.f);
	ImGui::Auto(v4,"v4");)code");
		static const glm::vec4 v4 = glm::vec4(v2, 3.14f,1.f);
		ImGui::Auto(v4,"v4");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static const glm::mat2 m2 = {1,2,3,4};
	ImGui::Auto(m2,"m2");)code");
		static const glm::mat2 m2 = {1,2,3,4};
		ImGui::Auto(m2,"m2");

		ImGui::NewLine(); ImGui::Separator();

		ImGui::Auto(R"code(
	static glm::mat4 m4 = glm::rotate<float>(14.5, glm::vec3{1.f,2.f,3.f});
	ImGui::Auto(m4,"m4");)code");
		static glm::mat4 m4 = glm::rotate<float>(14.5, glm::vec3{1.f,2.f,3.f});
		ImGui::Auto(m4,"m4");
	}
#endif // _IMGUI_AUTO_GLM_

	ImGui::End();
}

#else
	void ImGui::ShowAutoTestWindow(){}
#endif